<html>
<head>
<title>Test</title>
<style>
  plaintext img { vertical-align:middle; }
</style>

<script>

function handleSmile(plaintext,caret,text,re) {
  var sequence = re[0];
  var anchor = [bookmark:caret[0],caret[1] - sequence.length,false];
  var imgsrc = this.img;

  return plaintext.plaintext.update( (transaction) => {
    const [node1, offset1] = transaction.deleteRange(anchor[0],anchor[1],caret[0],caret[1]);
    const nodes = transaction.insertHTML(node1, offset1,"<img src='"+ imgsrc +"'/>");
    plaintext.selection.selectNodeContent(nodes[0]);
    plaintext.selection.collapseToEnd();
    return true; // done,commit
  });
}

var sequences = [];

sequences.push { re: RegExp(/\:\)$/, 'g'), fun: handleSmile, img: "sciter:copy.png" };
sequences.push { re: RegExp(/\:D$/, 'g'), fun: handleSmile, img: "sciter:paste.png" };

function checkForReplacement(plaintext,bm) {
  var node = bm[0];
  if(!node?.nodeType === 'text')
    return false;
  var lpos = bm[1] + (bm[2] ? 1 : 0); 
  
  var text = node.textContent;
  var start = text.substr(0,lpos);
  for(var sr of sequences) {
    var res = sr.re.exec(start);
    if( !res ) continue;
    if( sr.fun(plaintext,bm,start,res) )
      return true; // handled 
  }            
}

document.on('change', 'plaintext', function(evt, el) {
  const CHANGE_BY_INS_CHAR = 0;  // single char insertion
  const CHANGE_BY_INS_CHARS = 1; // character range insertion, clipboard
  const CHANGE_BY_DEL_CHAR = 2;  // single char deletion
  const CHANGE_BY_DEL_CHARS = 3; // character range deletion (selection)
  const CHANGE_BY_UNDO_REDO = 4;
  const CHANGE_BY_INS_CONSECUTIVE_CHAR = 5; // single char insertion, previous character was inserted in previous position  
  const CHANGE_BY_CODE = 6; 
  if(evt.reason == CHANGE_BY_INS_CONSECUTIVE_CHAR || evt.reason == CHANGE_BY_INS_CHAR){
    checkForReplacement(el,[el.selection.focusNode, el.selection.focusOffset, false]);
  }   
});

</script>
</head>
<body>
  Recognizes :) and :D emojis as <img src=sciter:copy.png> and <img src=sciter:paste.png> images.
  <plaintext tab-size=4>Line 1
Line 2
Line 3
Line 4
  </plaintext>    
</body>
</html>